#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "GConditionVar.h"
#include "GError.h"

namespace GThread
{
	// Description: Initializes the condition variable
	// Return: Returns false if condition variable is already created
	// Notes:
	// -----------------------------------------------------
	bool GConditionVar::Create()
	{
		if (IsCreated())
		{
			return false;
		}

		Variable = new CONDITION_VARIABLE;

		InitializeConditionVariable((PCONDITION_VARIABLE)Variable);

		return true;
	}

	// Description: Wakes one of the waiting threads for the condition variable
	// Return: returns false if not initialized, true otherwise
	// Notes:
	// -----------------------------------------------------
	bool GConditionVar::Wake() const
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Condition variable is not created.");

		WakeConditionVariable((PCONDITION_VARIABLE)Variable);

		return true;
	}

	// Description: Wakes all threads that are waiting for the condition variable
	// Return: returns false if not initialized, true otherwise
	// Notes:
	// -----------------------------------------------------
	bool GConditionVar::WakeAll() const
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Condition variable is not created.");

		WakeAllConditionVariable((PCONDITION_VARIABLE)Variable);

		return true;
	}

	// Description: Sleeps until the condition variable is waken up by another thread.
	// Return: returns one of the GWaitResult enums according to the result of function.
	// Notes: Returns G_WR_SIGNALED_0 on success.
	// -----------------------------------------------------
	GWaitResult GConditionVar::Wait(GCriticalSection* Section, GUInt32 TimeOut)
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Condition variable is not created.");

		BOOL Result = SleepConditionVariableCS((PCONDITION_VARIABLE)Variable, (LPCRITICAL_SECTION)Section->Section, TimeOut);
		if (Result == 0)
		{
			DWORD ErrCode = GetLastError();
			if (ErrCode == ERROR_TIMEOUT)
			{
				return G_WR_TIMEOUT;
			}
			else
			{
				GUtil::GError::Error(GUtil::GErrorMessageWin32(ErrCode));
				return G_WR_ERROR;	
			}
		}

		return G_WR_SIGNALED_0;
	}
}